package com.example.net1;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SealedObject;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

public class CryptoUtil {

	public static final String keyStore = "./keystore.jks";
	public static final String cert = "./serverCA.crt";

	public static  RSAPrivateKey getRSAprivateKey(String keyStoreName) throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException, UnrecoverableEntryException {

		KeyStore ks = KeyStore.getInstance("JKS");
		// to change
		char[] password = "moaad1988".toCharArray();
		java.io.FileInputStream fis =  new java.io.FileInputStream(keyStoreName);
		ks.load(fis,password);
		fis.close();

		KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) ks.getEntry("serverkey", new KeyStore.PasswordProtection(password));
		PrivateKey privateKey = pkEntry.getPrivateKey();
		RSAPrivateKey RSAPrivateKey = (RSAPrivateKey) privateKey;

		//		printHash("RSA private key Exponent: ", RSAPrivateKey.getPrivateExponent().toByteArray());
		//		printHash("RSA private key Modulus: ", RSAPrivateKey.getModulus().toByteArray());

		return RSAPrivateKey;
	}

	public static  RSAPublicKey getRSApublicKey(String pathToCert) {
		RSAPublicKey rsapub = null ;
		try {
			InputStream is = new FileInputStream(pathToCert);
			CertificateFactory cf = CertificateFactory.getInstance("X.509");
			X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
			is.close();
			rsapub = (RSAPublicKey) cert.getPublicKey();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (CertificateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

//		System.out.println("RSA public key Exponent: " + rsapub.getPublicExponent().toString());
//		System.out.println("RSA public key Modulus: " + rsapub.getModulus().toString());

		return rsapub;
	}

	/**
	 * 
	 * @param key
	 * @param RSApub
	 * @return
	 */
	private static byte[] encryptKey(String label, byte[] key, RSAPublicKey RSApub){

		Cipher c = null;
		try {
			c = Cipher.getInstance("RSA");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		}
		try {
			c.init(Cipher.ENCRYPT_MODE, RSApub);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
		byte[] cipherData = null;
		try {
			cipherData = c.doFinal(key);
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		//	printHash(label, cipherData);

		return cipherData;
	}

	/**
	 * 
	 * @param label
	 * @param key
	 * @param RSApub
	 * @return
	 */
	private static byte[] decryptKey(String label, byte[] enckey, RSAPrivateKey RSAprv){

		Cipher c = null;
		try {
			c = Cipher.getInstance("RSA");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		}
		try {
			c.init(Cipher.DECRYPT_MODE, RSAprv);
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
		byte[] fileHash = null;
		try {
			fileHash = c.doFinal(enckey);
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		//		printHash(label, fileHash);
		return fileHash;
	}


	public static SecretKey decryptKey(SealedObject encryptedObject, PrivateKey bankPrivateKey) throws BadPaddingException, ClassNotFoundException {
		SecretKey decryptedKey = null;
		try {
			Cipher cipher = Cipher.getInstance(bankPrivateKey.getAlgorithm());
			cipher.init(Cipher.DECRYPT_MODE, bankPrivateKey);
			decryptedKey = (SecretKey) encryptedObject.getObject(cipher);
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return decryptedKey;
	}

	public static Object decrypt(Serializable object, SecretKey key) throws BadPaddingException, ClassNotFoundException {
		Object decryptedObject = null;
		try {
			byte[] iv = {
					0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
					0x08, 0x09,0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
			};
			//			SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
			AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // /NoPadding");
			cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
			decryptedObject = ((SealedObject)object).getObject(cipher);
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidAlgorithmParameterException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return decryptedObject;
	}


//
//	public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchAlgorithmException, CertificateException, KeyStoreException, UnrecoverableEntryException  {
//		System.out.println(System.getProperty("user.dir"));
//		byte[] tab = {0,1,0,1,1};
//		byte[] decryptedKey =encryptKey(" ",tab,getRSApublicKey(cert));
//		byte[] original = decryptKey(" ", decryptedKey, getRSAprivateKey(keyStore));
//		System.out.println(Arrays.toString(original));
//	}
}
